//
// Created by user on 20-5-5.
//

#include "Schedule.h"

Schedule taskSchedule[NR_CPUS];

void scheduleInit() {

    memset(&taskSchedule, 0, sizeof(Schedule));

    for (int i = 0; i < NR_CPUS; ++i) {

        listInit(&taskSchedule[i].taskQueueHead.list);
        taskSchedule[i].taskQueueHead.vrunTime = 0x7fffffffffffffff;

        taskSchedule[i].runningTaskCount = 1;
        taskSchedule[i].CPUExecTaskJiffies = 4;

    }

}

void schedule() {
    Task *tsk = NULL;

    // 1. 将当前进程可调度位复位
    current->flags &= ~NEED_SCHEDULE;

    // 2. 获取到下一个进程的指针
    tsk = getNextTask();

    printfColor(RED, BLACK, "#- schedule: %d -#\n", jiffies);

    // 3. 判断当前进程的运行时间是否大于等于下一个进程的运行时间
    // 如果为真，就切换进程
    // 如果为假，就不切换进程，
    if (current->vrunTime >= tsk->vrunTime) {

        // 1> 如果当前进程的状态依然是运行状态，就把它插入到就绪队列里面
        if (current->state == TASK_RUNNING)
            insertTaskQueue(current);

        // 2> 根据下一个进程的优先级为它分配时间片
        if (!taskSchedule[SMPCPUID()].CPUExecTaskJiffies) {

            switch (tsk->priority) {
                case 0:
                case 1:
                    taskSchedule[SMPCPUID()].CPUExecTaskJiffies = 4 / taskSchedule[SMPCPUID()].runningTaskCount;
                    break;
                case 2:
                default:
                    taskSchedule[SMPCPUID()].CPUExecTaskJiffies = 4 / taskSchedule[SMPCPUID()].runningTaskCount * 3;
                    break;
            }

        }

        // 3> 切换进程
        switchTo(current, tsk);

    } else {
        insertTaskQueue(tsk);

        if (!taskSchedule[SMPCPUID()].CPUExecTaskJiffies)
            switch (tsk->priority) {
                case 0:
                case 1:
                    taskSchedule[SMPCPUID()].CPUExecTaskJiffies = 4 / taskSchedule[SMPCPUID()].runningTaskCount;
                    break;
                case 2:
                default:
                    taskSchedule[SMPCPUID()].CPUExecTaskJiffies = 4 / taskSchedule[SMPCPUID()].runningTaskCount * 3;
                    break;
            }
    }
}

Task *getNextTask() {
    Task *tsk = NULL;

    if (listIsEmpty(&taskSchedule[SMPCPUID()].taskQueueHead.list)) {
        return &initTaskUnion.task;
    }

    tsk = containerOf(listNext(&taskSchedule[SMPCPUID()].taskQueueHead.list),
                      Task, list);
    listDel(&tsk->list);

    taskSchedule[SMPCPUID()].runningTaskCount -= 1;

    return tsk;
}


void insertTaskQueue(Task *tsk) {
    Task *tmp = containerOf(listNext(&taskSchedule[SMPCPUID()].taskQueueHead.list), Task, list);

    if (tsk == &initTaskUnion.task)
        return;

    if (listIsEmpty(&taskSchedule[SMPCPUID()].taskQueueHead.list)) {
    } else {
        while (tmp->vrunTime < tsk->vrunTime)
            tmp = containerOf(listNext(&tmp->list),
                              Task, list);
    }

    listAddToBefore(&tmp->list, &tsk->list);
    taskSchedule[SMPCPUID()].runningTaskCount += 1;
}